//---------------------------------------------------------------------
//
// Author: jachymko
//
// Description: The Ping-Host command.
//
// Creation date: Dec 14, 2006
//
//---------------------------------------------------------------------
using System;
using System.ComponentModel;
using System.Management.Automation;
using System.Net;

namespace Pscx.Commands.Net
{
    [Cmdlet(VerbsDiagnostic.Ping, PscxNouns.Host, SupportsShouldProcess = true)]
    [Description("Sends ICMP echo requests to nework hosts.")]
    public partial class PingHostCommand : PSCmdlet, IDisposable
    {
        #region Parameters

        #region Parameter fields
        PSObject[] hosts;

        int ttl = 255;
        int count = 4;
        byte[] buffer = new byte[32];
        TimeSpan timeout = TimeSpan.FromMilliseconds(1000);

        SwitchParameter async;
        SwitchParameter allAddresses;
        #endregion

        #region Parameter properties
        
        [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true)]
        public PSObject[] HostName 
        {
            get { return hosts; }
            set { hosts = value; }
        }

        [Parameter(Position = 1, HelpMessage = "Number of messages to send to each address.")]
        [ValidateRange(1, int.MaxValue)]
        public int Count
        {
            get { return count; }
            set { count = value; }
        }

        [Parameter(Position = 2, HelpMessage = "Size of the message in bytes.")]
        [ValidateRange(1, 65000)]
        public int BufferSize
        {
            get { return buffer.Length; }
            set
            {
                buffer = new byte[value];
                random.NextBytes(buffer);
            }
        }

        [Parameter(Position = 3, HelpMessage = "Timeout in milliseconds to wait for each reply.")]
        [ValidateRange(1, int.MaxValue)]
        public int Timeout
        {
            get { return (int)timeout.TotalMilliseconds; }
            set { timeout = TimeSpan.FromMilliseconds(value); }
        }

        [Parameter(Position = 4, HelpMessage = "Time To Live.")]
        public int TTL
        {
            get { return ttl; }
            set { ttl = value; }
        }

        [Parameter(Position = 5, HelpMessage = "Pings the host on all IP addresses found.")]
        public SwitchParameter AllAddresses
        {
            get { return allAddresses; }
            set { allAddresses = value; }
        }

        [Parameter(Position = 6, HelpMessage = "Pings all hosts in parallel.")]
        public SwitchParameter Asynchronous
        {
            get { return async; }
            set { async = value; }
        }
        #endregion

        #endregion

        PingExecutor executor;

        public PingHostCommand()
        {
            random.NextBytes(buffer);
        }

        public void Dispose()
        {
            if(executor != null)
                executor.Dispose();
        }

        protected override void BeginProcessing()
        {
            if (async.IsPresent)
                executor = new PingExecutorAsync(this);
            else
                executor = new PingExecutorSync(this);

            executor.BeginProcessing();
        }

        protected override void ProcessRecord()
        {
            foreach(PSObject target in hosts)
            {
                if(ShouldProcess(target.ToString()))
                {
                    IPAddress address = target.BaseObject as IPAddress;
                    IPHostEntry hostEntry = target.BaseObject as IPHostEntry;
                    
                    if(hostEntry != null)
                    {
                        executor.Send(hostEntry);
                    }

                    if(address != null)
                    {
                        executor.Send(address);
                    }

                    executor.Send(target.ToString());
                }
            }
        }

        protected override void EndProcessing()
        {
            executor.EndProcessing();
        }

        protected override void StopProcessing()
        {
            if(executor != null)
                executor.StopProcessing();
        }

        internal byte[] Buffer { get { return buffer; } }

        static readonly Random random = new Random();
    }
}
